<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>请完成验证</title>
    <style>
        body,
        html {
            margin: 0;
            padding: 0;
            position: relative;
            width: 100%;
            height: 100%;
            font-family: "PingFangSC-Regular", "Open Sans", Arial, "Hiragino Sans GB", "Microsoft YaHei", "STHeiti", "WenQuanYi Micro Hei", SimSun, sans-serif;
        }

        body {
            display: flex;
            justify-content: center;
            align-items: center;
        }

        #captcha {
            width: 300px;
            display: inline-block;
        }

        #wait {
            height: 42px;
            width: 298px;
            text-align: center;
            border-radius: 2px;
            background-color: #F3F3F3;
        }

        .loading {
            margin: auto;
            width: 70px;
            height: 20px;
        }

        .loading-dot {
            float: left;
            width: 8px;
            height: 8px;
            margin: 18px 4px;
            background: #ccc;

            -webkit-border-radius: 50%;
            -moz-border-radius: 50%;
            border-radius: 50%;

            opacity: 0;

            -webkit-box-shadow: 0 0 2px black;
            -moz-box-shadow: 0 0 2px black;
            -ms-box-shadow: 0 0 2px black;
            -o-box-shadow: 0 0 2px black;
            box-shadow: 0 0 2px black;

            -webkit-animation: loadingFade 1s infinite;
            -moz-animation: loadingFade 1s infinite;
            animation: loadingFade 1s infinite;
        }

        .loading-dot:nth-child(1) {
            -webkit-animation-delay: 0s;
            -moz-animation-delay: 0s;
            animation-delay: 0s;
        }

        .loading-dot:nth-child(2) {
            -webkit-animation-delay: 0.1s;
            -moz-animation-delay: 0.1s;
            animation-delay: 0.1s;
        }

        .loading-dot:nth-child(3) {
            -webkit-animation-delay: 0.2s;
            -moz-animation-delay: 0.2s;
            animation-delay: 0.2s;
        }

        .loading-dot:nth-child(4) {
            -webkit-animation-delay: 0.3s;
            -moz-animation-delay: 0.3s;
            animation-delay: 0.3s;
        }

        @-webkit-keyframes loadingFade {
            0% {
                opacity: 0;
            }

            50% {
                opacity: 0.8;
            }

            100% {
                opacity: 0;
            }
        }

        @-moz-keyframes loadingFade {
            0% {
                opacity: 0;
            }

            50% {
                opacity: 0.8;
            }

            100% {
                opacity: 0;
            }
        }

        @keyframes loadingFade {
            0% {
                opacity: 0;
            }

            50% {
                opacity: 0.8;
            }

            100% {
                opacity: 0;
            }
        }
    </style>
</head>

<body>
    <div id="captcha">
        <div id="wait">
            <div class="loading">
                <div class="loading-dot"></div>
                <div class="loading-dot"></div>
                <div class="loading-dot"></div>
                <div class="loading-dot"></div>
            </div>
        </div>
    </div>

</body>
<script>
    "v0.4.8 Geetest Inc.";

    (function (window) {
        "use strict";
        if (typeof window === 'undefined') {
            throw new Error('Geetest requires browser environment');
        }

        var document = window.document;
        var Math = window.Math;
        var head = document.getElementsByTagName("head")[0];

        function _Object(obj) {
            this._obj = obj;
        }

        _Object.prototype = {
            _each: function (process) {
                var _obj = this._obj;
                for (var k in _obj) {
                    if (_obj.hasOwnProperty(k)) {
                        process(k, _obj[k]);
                    }
                }
                return this;
            }
        };

        function Config(config) {
            var self = this;
            new _Object(config)._each(function (key, value) {
                self[key] = value;
            });
        }

        Config.prototype = {
            api_server: 'api.geetest.com',
            protocol: 'http://',
            typePath: '/gettype.php',
            fallback_config: {
                slide: {
                    static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
                    type: 'slide',
                    slide: '/static/js/geetest.0.0.0.js'
                },
                fullpage: {
                    static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
                    type: 'fullpage',
                    fullpage: '/static/js/fullpage.0.0.0.js'
                }
            },
            _get_fallback_config: function () {
                var self = this;
                if (isString(self.type)) {
                    return self.fallback_config[self.type];
                } else if (self.new_captcha) {
                    return self.fallback_config.fullpage;
                } else {
                    return self.fallback_config.slide;
                }
            },
            _extend: function (obj) {
                var self = this;
                new _Object(obj)._each(function (key, value) {
                    self[key] = value;
                })
            }
        };
        var isNumber = function (value) {
            return (typeof value === 'number');
        };
        var isString = function (value) {
            return (typeof value === 'string');
        };
        var isBoolean = function (value) {
            return (typeof value === 'boolean');
        };
        var isObject = function (value) {
            return (typeof value === 'object' && value !== null);
        };
        var isFunction = function (value) {
            return (typeof value === 'function');
        };
        var MOBILE = /Mobi/i.test(navigator.userAgent);
        var pt = MOBILE ? 3 : 0;

        var callbacks = {};
        var status = {};

        var nowDate = function () {
            var date = new Date();
            var year = date.getFullYear();
            var month = date.getMonth() + 1;
            var day = date.getDate();
            var hours = date.getHours();
            var minutes = date.getMinutes();
            var seconds = date.getSeconds();

            if (month >= 1 && month <= 9) {
                month = '0' + month;
            }
            if (day >= 0 && day <= 9) {
                day = '0' + day;
            }
            if (hours >= 0 && hours <= 9) {
                hours = '0' + hours;
            }
            if (minutes >= 0 && minutes <= 9) {
                minutes = '0' + minutes;
            }
            if (seconds >= 0 && seconds <= 9) {
                seconds = '0' + seconds;
            }
            var currentdate = year + '-' + month + '-' + day + " " + hours + ":" + minutes + ":" + seconds;
            return currentdate;
        }

        var random = function () {
            return parseInt(Math.random() * 10000) + (new Date()).valueOf();
        };

        var loadScript = function (url, cb) {
            var script = document.createElement("script");
            script.charset = "UTF-8";
            script.async = true;

            // 对geetest的静态资源添加 crossOrigin
            if (/static\.geetest\.com/g.test(url)) {
                script.crossOrigin = "anonymous";
            }

            script.onerror = function () {
                cb(true);
            };
            var loaded = false;
            script.onload = script.onreadystatechange = function () {
                if (!loaded &&
                    (!script.readyState ||
                        "loaded" === script.readyState ||
                        "complete" === script.readyState)) {

                    loaded = true;
                    setTimeout(function () {
                        cb(false);
                    }, 0);
                }
            };
            script.src = url;
            head.appendChild(script);
        };

        var normalizeDomain = function (domain) {
            // special domain: uems.sysu.edu.cn/jwxt/geetest/
            // return domain.replace(/^https?:\/\/|\/.*$/g, ''); uems.sysu.edu.cn
            return domain.replace(/^https?:\/\/|\/$/g, ''); // uems.sysu.edu.cn/jwxt/geetest
        };
        var normalizePath = function (path) {
            path = path.replace(/\/+/g, '/');
            if (path.indexOf('/') !== 0) {
                path = '/' + path;
            }
            return path;
        };
        var normalizeQuery = function (query) {
            if (!query) {
                return '';
            }
            var q = '?';
            new _Object(query)._each(function (key, value) {
                if (isString(value) || isNumber(value) || isBoolean(value)) {
                    q = q + encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&';
                }
            });
            if (q === '?') {
                q = '';
            }
            return q.replace(/&$/, '');
        };
        var makeURL = function (protocol, domain, path, query) {
            domain = normalizeDomain(domain);

            var url = normalizePath(path) + normalizeQuery(query);
            if (domain) {
                url = protocol + domain + url;
            }

            return url;
        };

        var load = function (config, send, protocol, domains, path, query, cb) {
            var tryRequest = function (at) {

                var url = makeURL(protocol, domains[at], path, query);
                loadScript(url, function (err) {
                    if (err) {
                        if (at >= domains.length - 1) {
                            cb(true);
                            // report gettype error
                            if (send) {
                                config.error_code = 508;
                                var url = protocol + domains[at] + path;
                                reportError(config, url);
                            }
                        } else {
                            tryRequest(at + 1);
                        }
                    } else {
                        cb(false);
                    }
                });
            };
            tryRequest(0);
        };


        var jsonp = function (domains, path, config, callback) {
            if (isObject(config.getLib)) {
                config._extend(config.getLib);
                callback(config);
                return;
            }
            if (config.offline) {
                callback(config._get_fallback_config());
                return;
            }

            var cb = "geetest_" + random();
            window[cb] = function (data) {
                if (data.status == 'success') {
                    callback(data.data);
                } else if (!data.status) {
                    callback(data);
                } else {
                    callback(config._get_fallback_config());
                }
                window[cb] = undefined;
                try {
                    delete window[cb];
                } catch (e) {
                }
            };
            load(config, true, config.protocol, domains, path, {
                gt: config.gt,
                callback: cb
            }, function (err) {
                if (err) {
                    callback(config._get_fallback_config());
                }
            });
        };

        var reportError = function (config, url) {
            load(config, false, config.protocol, ['monitor.geetest.com'], '/monitor/send', {
                time: nowDate(),
                captcha_id: config.gt,
                challenge: config.challenge,
                pt: pt,
                exception_url: url,
                error_code: config.error_code
            }, function (err) { })
        }

        var throwError = function (errorType, config) {
            var errors = {
                networkError: '网络错误',
                gtTypeError: 'gt字段不是字符串类型'
            };
            if (typeof config.onError === 'function') {
                config.onError(errors[errorType]);
            } else {
                throw new Error(errors[errorType]);
            }
        };

        var detect = function () {
            return window.Geetest || document.getElementById("gt_lib");
        };

        if (detect()) {
            status.slide = "loaded";
        }

        window.initGeetest = function (userConfig, callback) {

            var config = new Config(userConfig);

            if (userConfig.https) {
                config.protocol = 'https://';
            } else if (!userConfig.protocol) {
                config.protocol = window.location.protocol + '//';
            }

            // for KFC
            if (userConfig.gt === '050cffef4ae57b5d5e529fea9540b0d1' ||
                userConfig.gt === '3bd38408ae4af923ed36e13819b14d42') {
                config.apiserver = 'yumchina.geetest.com/'; // for old js
                config.api_server = 'yumchina.geetest.com';
            }

            if (userConfig.gt) {
                window.GeeGT = userConfig.gt
            }

            if (userConfig.challenge) {
                window.GeeChallenge = userConfig.challenge
            }

            if (isObject(userConfig.getType)) {
                config._extend(userConfig.getType);
            }
            jsonp([config.api_server || config.apiserver], config.typePath, config, function (newConfig) {
                var type = newConfig.type;
                var init = function () {
                    config._extend(newConfig);
                    callback(new window.Geetest(config));
                };

                callbacks[type] = callbacks[type] || [];
                var s = status[type] || 'init';
                if (s === 'init') {
                    status[type] = 'loading';

                    callbacks[type].push(init);

                    load(config, true, config.protocol, newConfig.static_servers || newConfig.domains, newConfig[type] || newConfig.path, null, function (err) {
                        if (err) {
                            status[type] = 'fail';
                            throwError('networkError', config);
                        } else {
                            status[type] = 'loaded';
                            var cbs = callbacks[type];
                            for (var i = 0, len = cbs.length; i < len; i = i + 1) {
                                var cb = cbs[i];
                                if (isFunction(cb)) {
                                    cb();
                                }
                            }
                            callbacks[type] = [];
                        }
                    });
                } else if (s === "loaded") {
                    init();
                } else if (s === "fail") {
                    throwError('networkError', config);
                } else if (s === "loading") {
                    callbacks[type].push(init);
                }
            });

        };


    })(window);


</script>

<script>
    var socket = null;

    window.onload = function () {
        if (window.MainApplication == undefined) {
            let port = 8765;

            socket = new WebSocket(`ws://localhost:${port}`);

            socket.onopen = function () {
                data = {
                    "msg": "queryCaptchaInfo"
                };

                socket.send(JSON.stringify(data));
            };

            socket.onmessage = function (event) {
                let json = JSON.parse(event.data);

                if (json.msg == "queryCaptchaInfo") {
                    receiveMessage(json.data.gt, json.data.challenge)
                }
            };

            socket.onerror = function (event) {
                alert("无法连接至 Websocket 服务器，与程序通信失败");
            };
        }
    }

    function receiveMessage(gt, challenge) {
        document.querySelector('#wait').style.display = "block";
        initGeetest({
            // 以下 4 个配置参数为必须，不能缺少
            gt: gt,
            challenge: challenge,
            offline: false, // 表示用户后台检测极验服务器是否宕机
            new_captcha: true, // 用于宕机时表示是新验证码的宕机

            product: "popup", // 产品形式，包括：float，popup
            width: "300px",
            https: true
        }, handler);
    }

    var handler = function (captchaObj) {
        captchaObj.appendTo('#captcha');
        captchaObj.onReady(function () {
            document.querySelector('#wait').style.display = 'none';
        });
        captchaObj.onSuccess(function () {
            var result = captchaObj.getValidate();

            data = {
                "msg": "captchaResult",
                "data": {
                    "challenge": result.geetest_challenge,
                    "seccode": result.geetest_seccode,
                    "validate": result.geetest_validate
                }
            };

            if (window.MainApplication == undefined) {
                socket.send(JSON.stringify(data));
            }
            else {
                window.MainApplication.postMessage(JSON.stringify(data));
            }
        });
        captchaObj.onError(function(e) {
            window.MainApplication.postMessage(JSON.stringify({
                code: 100,
                msg: e.msg
            }));
        });
    };
</script>

</html>